/*
 * @Author: your name
 * @Date: 2021-10-27 08:11:56
 * @LastEditTime: 2022-03-02 19:40:39
 * @LastEditors: Please set LastEditors
 * @Description: 二级页管理类，如果一个页面需要对设置项进行选定操作，可继承此类进行管理
 * second_page是二级页属性，second_view是对second_page进行管理。
 * @FilePath: \phone\src\second_view.h
 */
#ifndef SECOND_VIEW_H
#define SECOND_VIEW_H
#include "interface.h"
#include "item.h"
#include "page_handle.h"
#include "second_page.h"
#include <mutex>
/**
 * @brief
 * 虚拟功能，当界面设置项个数随机时使用
 */
enum VirtualFuncV2 {
    FUNCTION_START = 0,
    VIRTUAL_END = 255 //虚拟设置项最多支持255个
};
class SecondView {
public:
    // SecondView();
    /**
     * @brief Construct a new Second Handle object
     * 本类被继承时，必须由派生类初始化的变量
     * @param itemTotal 设置项单页显示的最大的设置项数
     * @param page 派生类的窗口控件指针
     */
    SecondView(const unsigned int itemTotal, std::unique_ptr<Widget>& page);
    virtual ~SecondView() = default;
    /**
     * @brief
     * 打开一个新的设置界面窗口
     * @param win 窗口名称
     * @param event 窗口按键事件
     * @param page 窗口的指针，不能为nullptr
     * @param ctx 绑定给窗口的数据，暂未使用
     * @param repetion 界面是否可以重复打开，默认可以重复打开
     */
    static bool OpenNewPage(std::string win, KeyCmdMapTable event, PageHandle* page, void* ctx, bool repetion = false);
    void SecondPageReset(SecondPage* value);
    SecondPage& GetSecondPage();
    SecondPage* ReturnSecondPage();
    bool SecondPageValid();
    bool SwitchSelectedItemHandle(Widget* window, int funcSelected, int lastSelected);
    bool CreateItemHandleV3(unsigned int itemNum, Widget* window, int funcSelected, Widget* view2);
    void DestroyHandle(Widget* window, int itemNum);
    void StartDisplayHandle(Widget* window, int funcSelected, std::function<void(Widget*, int)> createOne, unsigned int maxItem = 4);
    void StartDisplayHandleV2(Widget* window, int funcSelected, std::function<void(Widget*, int)> createOne, unsigned int maxItem = 6);
    void RefreshItemHandle(void* ctx, void (*func)(void*));
    bool SwitchSelectedItem();
    void RefreshItemIQ3(void* ctx);
    void CreateItemsHandleV3(KeyboardValue key);
    void RefreshItem(void* ctx);
    void RefreshSlider();
    /**
     * @brief
     * 打开新窗口的设置项，一般没有设置项的值，所以要把设置项名称设置为100%宽度
     * @param target
     */
    void EnterItemHandle(unsigned int target);
    /**
     * @brief
     * 设置项的OK处理函数，一般是确定操作选定的设置项。
     * @param ctx
     */
    void KeyOkEvent(void* ctx);
    /**
     * @brief Get the String object
     * 获取设置项的字符数据时，有三个GetString函数，一个是Item类虚函数，一个是Item子类重写函数，一个是当前文件的模板函数；
     * 调用顺序是模板函数->重写函数，有点绕（主要是实现抽象的处理流程）
     * @param target
     * @param itemPtr
     * @return std::string
     */
    std::string GetString(unsigned int target);
    std::string GetStringTrText(unsigned int target);
    std::string GetTrText(unsigned int target);
    /**
     * @brief
     * 刷新所有数据。
     */
    void RefreshAllItem();
    /**
     * @brief
     * 刷新当前页显示的所有数据。
     * @param selected 当前页选中的项
     */
    void RefreshCurrentItem(unsigned int selected);
    virtual void Select(void* ctx);
    /**
     * @brief
     * 界面启动初始化，默认从第一个设置项开始。
     */
    virtual void StartDisplay();
    /**
     * @brief
     * 界面启动初始化函数2，带上下文参数。
     * @param ctx
     */
    virtual void StartDisplayV2(void* ctx);
    /**
     * @brief
     * 设置界面对设置数据的初始化抽象方法，由派生类（具体的设置界面）实现。暂未使用
     */
    virtual void InitData() { }
    /**
     * @brief 
     * 少数情况下，主机面恢复一些被二级页修改的控件。
     */
    virtual void PrimaryPageRecover() { }
    /**
     * @brief
     *
     * @return true
     * @return false
     */
    bool KeyCmdResetHandle();
    /**
     * @brief
     * 当前设置界面恢复按键事件，下一级窗口关闭时，可保持本界面按键功能正常。
     * @param ctx
     */
    void UnlockSecondPageV2(void* ctx);
    Widget* GetPrimaryPage();
    void SetFuncAmount(unsigned int amount);
    unsigned int GetFuncAmount();
    void SetSecondViewKeyEvent(KeyCmdMapTable event);
    void SetItemTotal(unsigned int total);
    /**
     * @brief Create a Item View object
     * 派生类的创建一个设置项view控件抽象函数
     * @param create 创建的设置项功能序号，标识view序号
     * @param view2 创建好的有效的view控件，注意该指针应该是有效的
     * @return true 创建失败
     * @return false 创建成功
     */
    virtual bool CreateItemView(int create, Widget* view2) { return false; }
    /**
     * @brief Create a One Item object
     * 派生类的创建一个设置项的抽象函数，不同的派生类（一般是一个界面类）可能会有不同的实现方法。
     * @param view2 创建好的有效的view控件，注意该指针应该是有效的
     * @param iTarget 创建的设置项功能序号，用于查找设置项的基本数据（名称译文、数值等）
     */
    virtual void CreateOneItem(Widget* view2, int iTarget) { }
    /**
     * @brief Set the Item View object
     * 派生类的设置设置项view控件的抽象函数，一般是设置view控件的布局、样式
     * @param view 需要设置的目标view控件，注意该指针应该是有效的
     */
    virtual void SetItemView(Widget* view) { }
    /**
     * @brief Set the Selected Item object
     * 派生类的设置被选中并“确定”操作的设置项的抽象函数，一般是设置操作状态下设置项的属性
     * @param view 被选中并“确定”操作的设置项view控件
     */
    virtual void SetSelectedItem(Widget* view) { }
    /**
     * @brief
     * 派生类的设置项被选择后不同界面的一些差异化操作，一般用于一些按键控件的显示/隐藏
     * 该方法在上下按键进行选择的时候触发，和ItemSelected方法性质不一样，根据实际情况使用。
     */
    virtual void ItemEvent() { }
    /**
     * @brief
     * 设置项是否是有效，默认返回true表示忽略；一般用于虚拟功能的设置项（设置项总数随机）。
     * @param target 设置项序号
     * @return true 设置项存在
     * @return false 设置项不存在
     */
    virtual bool TargetItemValid(unsigned int target) { return true; }
    /**
     * @brief
     * 设置项当前滚动条占比，用于虚拟功能的设置项，因为设置项总数随机，占比计算由派生类处理。
     * @param value 输出处理的占比
     * @return true 处理成功返回
     * @return false 处理失败返回，默认返回失败表示不存在虚拟功能
     */
    virtual bool VirtualSliderValue(int& value, unsigned int selected) { return false; }
    /**
     * @brief
     *
     */
    virtual void StartInitFunc();

public:
    /**
     * @brief
     * 当前选中设置项的实例，当对设置项进行操作时使用，
     * 一般情况下，设置设置项时，new一个实例，保存到智能指针，然后对该实例进行操作。
     */
    std::unique_ptr<SecondPage> secondPage;
    std::mutex m_mutex;
    /**
     * @brief
     * 主要的窗口，该类依赖一个窗口，控制主窗口的某个区域
     * 该指针只使用，不管理
     */
    // Widget **primaryPage;//弃用
    /**
     * @brief
     * 主要的窗口，该类依赖一个窗口，控制主窗口的某个区域
     */
    std::unique_ptr<Widget>& primaryWidget;
    /**
     * @brief
     * 当前功能选项
     */
    unsigned int funcSelected;
    /**
     * @brief
     * 上一个功能选择
     */
    unsigned int lastSelected;
    /**
     * @brief
     * 派生类设置页单页显示的最大设置项数量，超过这个数会进行翻页，翻页功能由本类实现。
     */
    unsigned int ITEM_TOTAL;
    /**
     * @brief
     * 设置项的实例，使用指针实现设置项的多态功能。
     */
    std::map<unsigned int, Item*> itemPtr;
    /**
     * @brief
     * 功能设置项的处理函数映射，一般用于设置项选定后，对设置项设置（数值改变、保存等）
     */
    std::map<unsigned int, std::function<void()>> reset;
    /**
     * @brief
     * 设置项选择是是否可以循环，例如最后一项的下一项是否可以循环切到第一项。
     * 默认为true
     */
    bool selectLoop;
    /**
     * @brief
     * 界面设置项总数。
     */
    unsigned int funcAmount;
    /**
     * @brief
     * 主界面的按键功能映射表。
     */
    KeyCmdMapTable keyEvent;
};
#endif